\section{Dise\~{n}o de un programa utilitario}

\noindent
\textbf{Dise\~{n}ar y programar un utilitario para el administrador del sistema, que permita crear, borrar o modificar en forma autom\'atica cuentas de usuarios. De forma interactiva pedir\'a todos los par\'ametros necesarios del nuevo usuario. Autom\'aticamente comprobar\'a y validar\'a el identificador del nuevo usuario. Crear\'a en caso de que no exista, su directorio asociado o directorio de trabajo, haci\'endolo su propietario. Asignar\'a al nuevo usuario un shell particular. Modificar\'a los archivos group y shadow con los nuevos valores. En caso que el grupo no exista deber\'a agregarlo. Deber\'a agregar el usuario al grupo. El borrado de un usuario llevar\'a consigo la desaparici\'on de todos sus archivos y directorios asociados y la modificaci\'on de los archivos group y shadow. En todos los casos deber\'a controlar la consistencia de la informaci\'on.}


Decidimos modularizar el problema, para lo que hicimos 4 scripts:\\

 \begin{itemize}
  \item Un script para crear una cuenta: \textbf{useradd}
  \item Un script para modificar una cuenta: \textbf{usermod}
  \item Un script para borrar una cuenta: \textbf{userdel}
  \item Un script para borrar un grupo: \textbf{groupdel}
 \end{itemize}


\begin{center}
\textbf{useradd}
\end{center} 

El programa para agregado de usuarios al sistema chequea que la cantidad de caracteres utilizados para el nombre de usuario y para el nombre del grupo estén entre 2 y 8 (requisitos de Minix). También se verifica que no haya un usuario con el mismo identificador que el que se pretende crear. Por otra parte, el programa también se ocupa de verificar si existe el grupo bajo el cual se pretende crear el usuario, en caso de que el mismo no exista, el programa creará uno nuevo.

Otra particularidad que tratamos fue la existencia o no del directorio del usuario y sus directorios superiores, es decir, que si el usuario decide que el directorio de trabajo es `/home/usuario' \ puede darse que el directorio no exista, pero también puede suceder que no exista el directorio `/home'. Ante una situación así el programa useradd crea el directorio de trabajo y todos los directorios superiores relacionados. Esto fue necesario, dado que el programa se basa en la aplicación \textit{adduser} disponible en Minix, la cual recibe un directorio que no debe existir, pero cuyo directorio padre sí debe existir.
El programa ofrece valores por defecto para todos los parámetros que solicita:
\begin{itemize}
	\item /usr/bin/ash para el shell.
	\item $<$user$>$ para el grupo, siendo $<$user$>$ el identificador de usuario indicado.
	\item /home/$<$user$>$ para el directorio de trabajo.
\end{itemize}

La contraseña debe ser agregada posteriormente mediante el comando passwd, dado que si bien pudimos solicitarla dos veces y chequear que sean iguales, no pudimos pasársela de manera silenciosa al comando passwd, que vuelve a pedir la misma.

Otra dificultad que encontramos al hacer los scripts, fue la imposibilidad de asignar a una variable el valor de otra variable con el operador `=', para esto tuvimos que hacer una combinación de comandos: $echo \ \$a | read \ b$ \ en lugar de $b=\$a$

Una dificultad parecida surgió con el \textit{if} de \textit{sh}. No encontramos la manera de hacer \textit{if} de la negación, por lo cuál adoptamos el ``truco'' de preguntar por la positiva utilizando la clausula \textit{else} para la negativa y rellenando la primera con una sentencia: $echo >/dev/null;$.

Este es el código:

\begin{verbatim}
#!/bin/sh


############################# NOMBRE DE USUARIO #############################

echo 'Ingrese el nombre de usuario: '
read user

# Si no ingresa un usuario dejo el prompt
until [ $user ]; do
	read user;
done

# Me fijo que no exista el usuario
while [ `grep -c '^'$user: /etc/passwd` -ne 0 ]; do
	echo "Usuario $user ya existe, ingrese un nuevo nombre: "
	read user;
done

# El usuario no puede tener mas de 8 digitos
while [ `expr $user : ".*"` -gt 8 ]; do
	echo "El usuario debe tener a lo sumo 8 caracteres. Ingreselo nuevamente: "
	read user;
done

# El usuario debe tener mas de un caracter
while [ `expr $user : ".*"` -le 1 ]; do
	echo "El usuario debe tener al menos dos caracteres. Ingreselo nuevamente: "
	read user;
done

####################### NOMBRE COMPLETO ################################

echo 'Ingrese el nombre completo del usuario []: '

read name

############################ GRUPO #####################################

echo 'Ingrese el nombre del grupo al que pertenecera el usuario ['$user']: '

read group

# El grupo no puede tener mas de 8 digitos
while [ $group ] && [ `expr $group : ".*"` -gt 8 ]; do
	echo "El grupo debe tener a lo sumo 8 caracteres. Ingreselo nuevamente: "
	read group;
done

############################### SHELL #################################

echo 'Ingrese el shell del usuario [/usr/bin/ash]: '

read shell

############################## DIRECTORIO ##############################

echo 'Ingrese el directorio home del usuario [/home/'$user']: '

read dir


############ COMPLETO CON LOS VALORES POR DEFECTO ####################

# Si no ingresa grupo le pongo el default
if [ $group ]; then
	echo >/dev/null;
else
	echo $user | read group;
fi

# Si no ingreso directorio le pongo /home/usuario
if [ $dir ]; then
	echo >/dev/null;
else
	echo "/home/"$user|read dir;
	echo "se setea el directorio: "$dir
fi

# Si no ingresa shell le pongo el ash
if [ $shell ]; then
	echo >/dev/null;
else
	echo "/usr/bin/ash" | read shell;
fi

echo "Las variables son: " $user $group $shell $dir

# Si el directorio ya existe hay q elegir otro
while [ -s $dir ]; do
	echo "El directorio ya existe, elija uno nuevo: "
	read $dir;
done


########################### HAGO EL ALTA #############################

# Me fijo que exista el grupo, si no lo agrego

if [ `grep -c '^'$group: /etc/group` -eq 0 ]; then
	echo "Agregando el grupo..."
	grep -v '^'nogroup: /etc/group|tail -n 1|cut -d : -f 3|read gid
	gid=`expr $gid + 1`
	echo $gid
	echo "$group:*:$gid:">> /etc/group
	sed "/\^\$/d" /etc/group >> /etc/group.tmp
	mv /etc/group.tmp /etc/group;
else
	echo "El grupo ya existe";
fi

# Chequeo que exista el directorio padre, si no lo creo
echo $dir| sed 's/\/[^\/]*$//'|read parentdir
if [ -z $parentdir ] || [ -d $parentdir ]; then
	echo "Existe el directorio padre"
else
	echo "Creando el directorio padre... "$parentdir
	mkdir -p $parentdir
fi

echo "Agregando usuario..."
adduser $user $group $dir
echo "Seteando nombre..."$name
if [ $name ]; then
	chfn $user "$name";
fi
echo "Seteando el shell..."
chsh $user $shell

\end{verbatim}

Este es el código que habíamos utilizado para el ingreso de la contraseña por parte del usuario:

\begin{verbatim}
	# verificamos que las contrasenias sean iguales		
		echo 'Ingrese la contrasenia: '
		read pas 
		echo 'Ingrese nuevamente la contrasenia: '
		read pass
		while test $pas != $pass ; do
			echo 'Las contrasenias no coinciden, vuelva a ingresarla: '
			read pas
			echo 'Ingresela nuevamente: ' 
			read pass;
		done
		
\end{verbatim} 

\begin{center}
\textbf{usermod}
\end{center} 

Para usermod ya contábamos con la experiencia de useradd en cuanto a problemas y soluciones de trabajar con la versión de bash que viene con Minix. La única diferencia fue que para lograr que sed hiciera las operaciones sobre los archivos \textit{passwd} y \textit{shadow} con los resultados deseados, fue necesario cambiar el interprete por \textit{/usr/bin/ash} en lugar de \textit{/bin/sh}.

Otro ingrediente interesante del uso de sed, fue la necesidad de cambiar el separador por defecto `\textit{/}' \ por `\textit{\_}' \ para poder manipular los directorios, dado que la nomenclatura de directoios incluye a dicho caracter (`\textit{/}').

	\begin{verbatim}
#!/usr/bin/ash

if [ $1 ]; then
	echo "Elija el parametro a modificar:"
	echo "   1) Grupo"
	echo "   2) Home Directory"
	echo "   3) Shell"
	echo "   4) Nombre"
	echo "   5) Password"
	echo "Opcion: "
	read opcion
	until [ $opcion ]; do 
		read opcion;
	done
	case "$opcion" in
		1)
			echo "Cambiando el grupo para el usuario: $1" 
			echo "Ingrese el nuevo numero de grupo para el usuario: "
			read grupo 
			until [ $grupo ]; do
				read grupo;
			done
			sed "s_\($1:##$1:[0-9]*:\)[0-9]*:_\1$grupo:_" /etc/passwd > /tmp/passwd 
			cp /tmp/passwd /etc/passwd
			echo "Cambio efectuado";
			;;
		2)
			echo "Cambiando el directorio de trabajo del usuario: " $1
			echo "Ingrese el nuevo directorio de trabajo: "
			read home 
			until [ $home ]; do
				read home;
			done
			sed "s_\($1:##$1:[0-9]*:[0-9]*:.*:\).*:_\1$home:_" /etc/passwd > /tmp/passwd 
			mv /tmp/passwd /etc/passwd
			echo "Cambio efectuado";
			;;

		3)
			echo "Cambiando el shell por defecto para el usuario " $1
			echo "Ingrese el nuevo shell: "
			read shell
			until [ $shell ]; do
				read shell;
			done
            		chsh $1 $shell
			echo "Cambio efectuado";
			;;
		4) 
			echo "Cambiando el nombre completo del usuario: " $1
			echo "Ingrese el nuevo apellido: "
			read surname
			until [ $surname ]; do
				read surname;
			done
			echo "Ingrese el nuevo nombre: "
			read name
			until [ $name ]; do
				read name;
			done
            		chfn $1 $name\ $surname
			echo "Cambio efectuado";
			;;
		5)
			echo "Cambio de password"
			passwd $1;
			;;
		*)
			echo "cualquier cosa";
			;;
	esac
else
	echo "Debe introducir el usuario a modificar luego del comando.";
	echo "Ejemplo: ./usermod ast";
fi

	\end{verbatim} 


\begin{center}
\textbf{userdel}
\end{center} 

Esta aplicación borra el usuario de los archivos \textit{passwd} y \textit{shadow} y todos los archivos y directorios pertenecientes al mismo, estén o no en su directorio de trabajo.

	\begin{verbatim}
#!/bin/sh
if [ $1 ]; then
	grep '^'$1: /etc/passwd| read pswd
	echo $pswd| cut -d : -f 6 | read dir
	rm -rf `find / -user $1`
	sed "s/\^$1:.*//" /etc/passwd | sed "/\^\$/d" > /etc/passwd.tmp
	sed "s/\^$1:.*//" /etc/shadow | sed "/\^\$/d" > /etc/shadow.tmp
	mv /etc/passwd.tmp /etc/passwd
	mv /etc/shadow.tmp /etc/shadow
	#sed "s/\^.*:.*:$gid:.*"$"//" /etc/group;
	#rm -rf $dir
else
	echo "Debe introducir el usuario a eliminar luego del comando.";
fi

	\end{verbatim} 

\begin{center}
\textbf{groupdel}
\end{center} 

Esta aplicación borra el grupo pasado como parámetro del archivo \textit{group}.

	\begin{verbatim}
#!/bin/sh
if [ $1 ]; then
	sed "s/\^$1:.*//" /etc/group | sed "/\^\$/d">> /tmp/group
	mv /tmp/group /etc/group
else
	echo "Debe introducir el grupo a eliminar luego del comando.";
fi
	\end{verbatim} 
